﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;

namespace ArmoryAPI
{
    /// <summary>
    /// The regions supported by the Battle.net RESTful API
    /// </summary>
    public enum BattleNetRegion
    {
        /// <summary>
        /// America
        /// </summary>
        America = 0,

        /// <summary>
        /// Europe
        /// </summary>
        Europe = 1,

        /// <summary>
        /// Korea
        /// </summary>
        Korea = 2,

        /// <summary>
        /// Taiwan
        /// </summary>
        Taiwan = 3,

        /// <summary>
        /// China
        /// </summary>
        China = 4
    }

    /// <summary>
    /// The locales supported by the Battle.net RESTful API
    /// </summary>
    public enum BattleNetLocale
    {
        /// <summary>
        /// US
        /// </summary>
        en_US = 0,

        /// <summary>
        /// MX
        /// </summary>
        es_MX = 1,

        /// <summary>
        /// GB
        /// </summary>
        en_GB = 2,

        /// <summary>
        /// ES
        /// </summary>
        es_ES = 3,

        /// <summary>
        /// FR
        /// </summary>
        fr_FR = 4,

        /// <summary>
        /// RU
        /// </summary>
        ru_RU = 5,

        /// <summary>
        /// DE
        /// </summary>
        de_DE = 6,

        /// <summary>
        /// KR
        /// </summary>
        ko_KR = 7,

        /// <summary>
        /// TW
        /// </summary>
        zh_TW = 8,

        /// <summary>
        /// CN
        /// </summary>
        zh_CN = 9
    }

    /// <summary>
    /// Provides functionality to interact with the Battle.net RESTful API
    /// </summary>
    public class Armory
    {
        #region Members

            private String _connectionString;
            private BattleNetLocale _locale;
            private BattleNetRegion _region;
            private int _refreshInterval;
            private bool _autoRefresh;

        #endregion

        #region Properties

            /// <summary>
            /// The connection string to be used when accessing cache in the database
            /// </summary>
            public String ConnectionString
            {
                get
                {
                    return _connectionString;
                }
                set
                {
                    _connectionString = value;
                }
            }

            /// <summary>
            /// The locale to return the data in
            /// </summary>
            public BattleNetLocale Locale
            {
                get
                {
                    return _locale;
                }
                set
                {
                    _locale = value;
                }
            }

            /// <summary>
            /// The region of the armory that will be used when fetching the data
            /// </summary>
            public BattleNetRegion Region
            {
                get
                {
                    return _region;
                }
                set
                {
                    _region = value;
                }
            }

            /// <summary>
            /// The number of minutes cached data should be considered valid data
            /// </summary>
            public int RefreshInterval
            {
                get
                {
                    return _refreshInterval;
                }
                set
                {
                    if (value > 0)
                    {
                        _refreshInterval = value;
                    }
                }
            }

            /// <summary>
            /// Indicates whether or not data should automatically be refreshed if it has expired
            /// </summary>
            public bool AutoRefresh
            {
                get
                {
                    return _autoRefresh;
                }
                set
                {
                    _autoRefresh = value;
                }
            }

        #endregion

        #region Instance Methods

            /// <summary>
            /// Returns an achievement object based on the identifier specified. 
            /// If no connection string was specified this data will be accessed via the RESTful API.
            /// </summary>
            /// <param name="id">The unique identifier of the achievement</param>
            /// <returns>An Achievement</returns>
            public Achievement GetAchievement(int id)
            {
                Achievement retval = new Achievement();

                // If the connection string is empty, use the RESTful API
                if (String.IsNullOrEmpty(_connectionString))
                {
                    WebRequest request = new WebRequest(_region, _locale);
                    retval = request.GetAchievementByID(id);
                }
                else
                {
                    DatabaseRequest request = new DatabaseRequest(_connectionString, _region, _locale);
                    retval = request.GetAchievementByID(id);
                }

                return retval;
            }

            /// <summary>
            /// Returns an ICollection containing all the achievements in World of Warcraft including Feats of Strength.
            /// If no connection string was specified this data will be accessed via the RESTful API.
            /// </summary>
            /// <returns>An ICollection of Achievements</returns>
            public ICollection<Achievement> GetAllAchievements()
            {
                ICollection<Achievement> retval;

                // If the connection string is empty, use the RESTful API
                if (String.IsNullOrEmpty(_connectionString))
                {
                    WebRequest request = new WebRequest(_region, _locale);
                    retval = request.GetAllAchievements();
                }
                else
                {
                    DatabaseRequest request = new DatabaseRequest(_connectionString, _region, _locale);
                    retval = request.GetAllAchievements();
                }

                return retval;
            }

            /// <summary>
            /// Returns a Character object based on the character and realm specified.
            /// If no connection string was specified this data will be accessed via the RESTful API.
            /// </summary>
            /// <param name="character">The character name</param>
            /// <param name="realm">The realm name in standard or friendly format</param>
            /// <returns>A Character</returns>
            public Character GetCharacter(String character, String realm)
            {
                Character retval = new Character();

                // If the connection string is empty, use the RESTful API
                if (String.IsNullOrEmpty(_connectionString))
                {
                    WebRequest request = new WebRequest(_region, _locale);
                    retval = request.GetCharacter(character, realm, null);
                }
                else
                {
                    DatabaseRequest request = new DatabaseRequest(_connectionString, _region, _locale);
                    retval = request.GetCharacter(character, realm, _refreshInterval, _autoRefresh);
                }

                return retval;
            }

            /// <summary>
            /// Returns a Guild object based on the guild name and realm specified.
            /// If no connection string was specified this data will be accessed via the RESTful API.
            /// </summary>
            /// <param name="name">The name of the guild</param>
            /// <param name="realm">The realm name in standard or friendly format</param>
            /// <returns>A Guild</returns>
            public Guild GetGuild(String name, String realm)
            {
                Guild retval = new Guild();

                // If the connection string is empty, use the RESTful API
                if (String.IsNullOrEmpty(_connectionString))
                {
                    WebRequest request = new WebRequest(_region, _locale);
                    retval = request.GetGuild(name, realm);
                }
                else
                {
                    DatabaseRequest request = new DatabaseRequest(_connectionString, _region, _locale);
                    retval = request.GetGuild(name, realm, _refreshInterval, _autoRefresh);
                }

                return retval;
            }

            /// <summary>
            /// Returns the requested Realm object.
            /// If no connection string was specified this data will be accessed via the RESTful API.
            /// </summary>
            /// <param name="name">The name of the realm</param>
            /// <returns>A Realm</returns>
            public Realm GetRealm(String name)
            {
                Realm retval = new Realm();

                // If the connection string is empty, use the RESTful API
                if (String.IsNullOrEmpty(_connectionString))
                {
                    WebRequest request = new WebRequest(_region, _locale);
                    retval = request.GetRealm(name);
                }
                else
                {
                    DatabaseRequest request = new DatabaseRequest(_connectionString, _region, _locale);
                    retval = request.GetRealm(name, _refreshInterval, _autoRefresh);
                }

                return retval;
            }

            /// <summary>
            /// Refreshes all the static data that is cached in the database such as achievements and quests.
            /// </summary>
            /// <returns>True on success, false on error</returns>
            public bool RefreshStaticData()
            {
                if (String.IsNullOrEmpty(_connectionString))
                {
                    return false;
                }
                else
                {
                    DatabaseRequest request = new DatabaseRequest(_connectionString, _region, _locale);
                    return request.RefreshAchievements();
                }
            }

        #endregion

        #region Constructors

            /// <summary>
            /// Constructs a new Armory with the specified region and locale
            /// </summary>
            /// <param name="region">The region to fetch data from</param>
            /// <param name="locale">The locale to return the data in</param>
            public Armory(BattleNetRegion region, BattleNetLocale locale)
            {
                _region = region;
                _locale = locale;
                _autoRefresh = true;
                _refreshInterval = 20;
            }

            /// <summary>
            /// Constructs an Armory object with the region and locale set to Europe/en_GB
            /// </summary>
            public Armory()
            {
                _locale = BattleNetLocale.en_GB;
                _region = BattleNetRegion.Europe;
                _refreshInterval = 0;
            }

        #endregion

        #region Static Methods

            /// <summary>
            /// Returns the abbreviation for the given region, e.g. "eu" for Europe
            /// </summary>
            /// <param name="region">The region</param>
            /// <returns>A string</returns>
            public static string GetRegionAbbreviation(BattleNetRegion region)
            {
                switch (region)
                {
                    case BattleNetRegion.America:
                        return "us";

                    case BattleNetRegion.China:
                        return "cn";

                    case BattleNetRegion.Europe:
                        return "eu";

                    case BattleNetRegion.Korea:
                        return "kr";

                    case BattleNetRegion.Taiwan:
                        return "tw";

                    default:
                        return "us";
                }
            }

            /// <summary>
            /// Returns the region specific portion of the API base e.g. us.battle.net
            /// </summary>
            /// <param name="region">The region</param>
            /// <returns>A string</returns>
            public static string GetAPIBase(BattleNetRegion region)
            {
                switch (region)
                {
                    case BattleNetRegion.America:
                        return "us.battle.net";

                    case BattleNetRegion.China:
                        return "battlenet.com.cn";

                    case BattleNetRegion.Europe:
                        return "eu.battle.net";

                    case BattleNetRegion.Korea:
                        return "kr.battle.net";

                    case BattleNetRegion.Taiwan:
                        return "tw.battle.net";

                    default:
                        return "us.battle.net";
                }
            }

        #endregion
    }
}
